//
//      ===  Demo LCDSmartie Plugin for c#  ===
//
// dot net plugins are supported in LCD Smartie 5.3 beta 3 and above.
//

// You may provide/use upto 20 functions (function1 to function20).

using System;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Net;
using System.Net.Sockets;


namespace vlc
{
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    public class LCDSmartie
    {
        private TcpClient myTcpClient;
        //  public static ManualResetEvent connectDone = new ManualResetEvent(false);
        private bool connecting;

        public LCDSmartie() { connecting = false; }

        private int connect()
        {
            try
            {
                /*Socket mySock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                mySock.bl
                mySock.Connect(IPAddress.Loopback, 4112);
                */
                myTcpClient = new TcpClient();
                myTcpClient.SendTimeout = myTcpClient.ReceiveTimeout = 5;
                //               myTcpClient.Connect("localhost", 4112);
                if (!connecting)
                {
                    connecting = true;
                    myTcpClient.BeginConnect(IPAddress.Loopback, 4112, new AsyncCallback(connectCallback), myTcpClient);
                }
                return 0;
            }
            catch { return -1; }
        }
        private void connectCallback(IAsyncResult result)
        {
            myTcpClient = (TcpClient)result.AsyncState;
            try
            {
                connecting = false;
                myTcpClient.EndConnect(result);
            }
            catch { }
        }

        // This function is used in LCDSmartie by using the dll command as follows:
        //    $dll(itunes2,1,<Command>,)
        // Smartie will then display on the LCD: 
        public string function1(string param1, string param2)
        {
            string recived;
            try
            {
                switch (param1)
                {
                    case "Title":
                        return send("get_title").Trim();
                    case "Filename":
                        recived = send("status");
                        try
                        {
                            recived = recived.Substring(recived.IndexOf("input:") + 7);
                            recived = recived.Substring(0, recived.IndexOf(" )"));
                            return recived;
                        }
                        catch (Exception) { return ""; }
                    /*
                        if(it.CurrentStreamTitle != null)
                            return it.CurrentStreamTitle;
                        return it.CurrentTrack.Artist + " - " + it.CurrentTrack.Name;
              /*
                    case "KBPS":
                        return it.CurrentTrack.BitRate.ToString();
                    case "Freq":
                        return (it.CurrentTrack.SampleRate/1000).ToString("00");

                     */
                     case "Stat":
                        recived = send("is_playing");
                        if(recived.Contains("1"))
                         return "playing";
                     return "not playing";
                  
                    case "Position":
                        return position(int.Parse(param2), float.Parse(send("get_length")), float.Parse(send("get_time")));
                    case "Polo":
                        return sec2hrsminsec(int.Parse(send("get_time")), false);
                    case "Posh":
                        return sec2hrsminsec(int.Parse(send("get_time")), true);
                    case "pos":
                        return int.Parse(send("get_time")).ToString("0");

                    case "Time":
                        return sec2min(int.Parse(send("get_time")));
                    case "Len":
                        return sec2min(int.Parse(send("get_length")));

                    case "Relo":
                        return sec2hrsminsec(int.Parse(send("get_length")) - int.Parse(send("get_time")), false);
                    case "Resh":
                        return sec2hrsminsec(int.Parse(send("get_length")) - int.Parse(send("get_time")), true);
                    case "Rem":
                        return (int.Parse(send("get_length")) - int.Parse(send("get_time"))).ToString();
                    case "Lengtl":
                        return sec2hrsminsec(int.Parse(send("get_length")), false);
                    case "Lengts":
                        return sec2hrsminsec(int.Parse(send("get_length")), true);
                    case "Length":
                        return int.Parse(send("get_length")).ToString("0");

                    case "Chapter":
                        recived = send("chapter");
//                        int i = ;
                        recived = recived.Substring(26);
                        recived = recived.Substring(0, recived.IndexOf("/"));
//                        recived = recived.Substring(0,recived.IndexOf("/"));
                        return (int.Parse(recived) + 1).ToString("0");
                    case "ChapterTot":
                        recived = send("chapter");
                        recived = recived.Substring(recived.IndexOf("/")+1, recived.IndexOf("\r"));
                        recived = recived.Substring(0, recived.IndexOf('.'));
                        return (int.Parse(recived) + 1).ToString("0");
                    /*      case "Tracknr":
                              return it.CurrentTrack.Index.ToString("0");
                          case "TotalTracks":
                              return it.CurrentPlaylist.Tracks.Count.ToString("0");
                          case "PlayList":
                              return it.CurrentPlaylist.Name;

                          case "Channels":
                      */
                    default:
                        return "Not implemented (yet)";
                }
            }
            catch (System.FormatException)
            {
                return "";
            }
            catch (Exception e)
            {
                return e.Message;
            }
        }

        private string send(string toSend)
        {
            if (myTcpClient == null)
            {
                if (connect() != 0)
                {
                    return "Could not connect to VLC";
                }
                //               Thread.Sleep(20);
            }
            if (!myTcpClient.Connected)
            {
                myTcpClient = null;
                return "No connection to VLC.";
            }

            myTcpClient.NoDelay = true;
            NetworkStream ns = myTcpClient.GetStream();
            Byte[] tosend = Encoding.ASCII.GetBytes(toSend + "\r\n");
            ns.Write(tosend, 0, tosend.Length);
            string expectedString = "";
            switch (toSend)
            {
                case "status":
                    expectedString = "(no error)\r\n";
                    break;
                //              case "get_length":
                case "chapter":
                    expectedString = "error)\r\n";
                    break;
                default:
                    expectedString = "\r\n";
                    break;
            }
            #region MyRegion
            /*
                 Byte[] bytes = new Byte[1];
                      int bytesReceived = 0;
                      myTcpClient.
                      do
                      {
                          bytesReceived = ns.Read(bytes, 0, bytes.Length);
                          received = received + Encoding.ASCII.GetString(bytes, 0, bytesReceived);
                      } while (myTcpClient.Available > 0 ); //&& bytes != Encoding.ASCII.GetBytes("[EOF]"));
             */

            #endregion
            string received = string.Empty;
            // Buffer to store the response bytes.
            Byte[] data = new Byte[256];

            // String to store the response ASCII representation.
            String responseData = String.Empty;

            // Read the first batch of the TcpServer response bytes.
            while (!responseData.Contains(expectedString))
            {
                Int32 bytes = ns.Read(data, 0, data.Length);
                responseData += System.Text.Encoding.ASCII.GetString(data, 0, bytes);
            }
#if (DEBUG)
            System.Diagnostics.Debug.WriteLine("Received: {0}", responseData);
            //         System.Diagnostics.Debug.WriteLine("Server.run recived[1]:\r\n" + received);
#endif
            return responseData;
            //return received;
        }


        //
        // Define the minimum interval that a screen should get fresh data from our plugin.
        // The actual value used by Smartie will be the higher of this value and of the "dll check interval" setting
        // on the Misc tab.  [This function is optional, Smartie will assume 300ms if it is not provided.]
        // 
        public int GetMinRefreshInterval()
        {
            return 300; // 300 ms (around 3 times a second)
        }

        private string sec2hrsminsec(int secs, bool shortFormat)
        {
            int hrs = (secs / 3600);
            int min = (secs / 60) - (hrs * 60);
            int sec = secs - (min * 60) - (hrs * 3600);

            if (shortFormat)
            {
                if (hrs > 0)
                    return hrs.ToString("#0:") + min.ToString("00:") + sec.ToString("00");
                if (min > 0)
                    return min.ToString("#0:") + sec.ToString("00");
                return sec.ToString();
            }
            if (hrs > 0)
                return hrs.ToString() + "hrs " + min.ToString("00") + "min " +
                    sec.ToString("00") + "sec";
            if (min > 0)
                return min.ToString("#0") + "min " +
                    sec.ToString("00") + "sec";
            return sec.ToString() + "sec";
        }

        private string sec2min(int sec)
        {
            int minutes = (sec / 60);
            int seconds = sec - (minutes * 60);
            return minutes.ToString("#0") + ":" + seconds.ToString("00");
        }

        private string position(int len, float length, float curpos)
        {
            string toReturn = "";
            for (int i = 0; i < (len - 1); i++)
                toReturn += "-";
            //lenght /= len;
            //curpos /= len;
            //	toReturn += lenght.ToString() + " "+ curpos.ToString() + " " + ((curpos/lenght)).ToString();
            if (length == 0)
                return toReturn;
            int j = (int)(len * (curpos / length));
            toReturn = toReturn.Insert(j, "+");
            return toReturn;
        }
    }
}

